package com.hmall.es;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.hmall.item.ItemApplication;
import com.hmall.item.domain.po.Item;
import com.hmall.item.domain.po.ItemDoc;
import com.hmall.item.service.IItemService;
import org.apache.http.HttpHost;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import javax.naming.directory.SearchResult;
import java.io.IOException;
import java.util.List;

public class esSearchTestClass {
    // 进行初始化
    private RestHighLevelClient client;
    @Autowired
    private IItemService iItemService;
    @BeforeEach
    void setUp() {
        this.client = new RestHighLevelClient(RestClient.builder(
                HttpHost.create("http://192.168.100.100:9200")
        ));
    }
    @AfterEach
    void tearDown() throws IOException {
        this.client.close();
    }
    // 搜索
    @Test
    public void testSearch() throws IOException {
        // 创建请求对象
        SearchRequest request = new SearchRequest("item");
        // 请求体
        request.source().query(QueryBuilders.matchAllQuery());
        // 请求
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        // 获取结果
        SearchHits result = response.getHits();
        // 获取结果中的数据条数
        long count = result.getTotalHits().value;
        System.out.println(count);
        // 获取数据
        SearchHit[] hits = result.getHits();
        // 遍历
        for (SearchHit hit : hits) {
            String json = hit.getSourceAsString();
            ItemDoc itemDoc = JSONUtil.toBean(json, ItemDoc.class);
            System.out.println(itemDoc);
        }
    }

    // 构建查询单条件
    @Test
    public void testBuildQuery() throws IOException {
        // 创建请求对象
        SearchRequest request = new SearchRequest("item");
        // 请求体
        request.source().query(QueryBuilders.matchQuery("name", "手机"));
        // 请求
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        SearchHits result = response.getHits();
        long count = result.getTotalHits().value;
        System.out.println(count);
        for (SearchHit hit : result.getHits()) {
            String json = hit.getSourceAsString();
            ItemDoc itemDoc = JSONUtil.toBean(json, ItemDoc.class);
            System.out.println(itemDoc);
        }
    }

    // 构建查询多条件
    @Test
    public void testBuildMultiQuery() throws IOException {
        // 创建请求对象
        SearchRequest request = new SearchRequest("item");
        // 请求体
        request.source().query(QueryBuilders.multiMatchQuery("脱脂牛奶","name", "category"));
        // 请求
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        SearchHits result = response.getHits();
        long count = result.getTotalHits().value;
        System.out.println(count);
        for (SearchHit hit : result.getHits()) {
            String json = hit.getSourceAsString();
            ItemDoc itemDoc = JSONUtil.toBean(json, ItemDoc.class);
            System.out.println(itemDoc);
        }
    }

    // 构建查询精确条件
    @Test
    public void testBuildTermQuery() throws IOException {
        // 创建请求对象
        SearchRequest request = new SearchRequest("item");
        // 请求体
        request.source().query(QueryBuilders.termQuery("category","牛奶"));
        // 请求
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        SearchHits result = response.getHits();
        long count = result.getTotalHits().value;
        System.out.println(count);
        for (SearchHit hit : result.getHits()) {
            String json = hit.getSourceAsString();
            ItemDoc itemDoc = JSONUtil.toBean(json, ItemDoc.class);
            System.out.println(itemDoc);
        }
    }

    // 构建查询范围条件
    @Test
    public void testBuildRangeQuery() throws IOException {
        // 创建请求对象
        SearchRequest request = new SearchRequest("item");
        // 请求体
        request.source().query(QueryBuilders.rangeQuery("price").gte(100000).lte(200000));
        // 请求
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        SearchHits result = response.getHits();
        long count = result.getTotalHits().value;
        System.out.println(count);
        for (SearchHit hit : result.getHits()) {
            String json = hit.getSourceAsString();
            ItemDoc itemDoc = JSONUtil.toBean(json, ItemDoc.class);
            System.out.println(itemDoc);
        }
    }

    // 构建复合查询的bool条件
    @Test
    public void testBuildBoolQuery() throws IOException {
        // 创建请求对象
        SearchRequest request = new SearchRequest("item");
        // 请求体
        request.source().query(
                QueryBuilders.boolQuery()
                        .must(QueryBuilders.termQuery("category","牛奶"))
                        .should(QueryBuilders.multiMatchQuery("脱脂牛奶","name", "category"))
                        .filter(QueryBuilders.rangeQuery("price").lte(25000)
        ));
        // 请求
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        SearchHits result = response.getHits();
        long count = result.getTotalHits().value;
        System.out.println(count);
        for (SearchHit hit : result.getHits()) {
            String json = hit.getSourceAsString();
            ItemDoc itemDoc = JSONUtil.toBean(json, ItemDoc.class);
            System.out.println(itemDoc);
        }
    }

    // 实践
    @Test
    public void testBuildMultiBoolQuery() throws IOException {
        // 创建请求对象
        SearchRequest request = new SearchRequest("item");
        // 请求体
        request.source().query(
                QueryBuilders.boolQuery()
                        .must(QueryBuilders.matchQuery("name","脱脂牛奶"))
                        .filter(QueryBuilders.termQuery("brand","德亚"))
                        .filter(QueryBuilders.rangeQuery("price").lte(30000)
                        ));
        // 请求
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        SearchHits result = response.getHits();
        long count = result.getTotalHits().value;
        System.out.println(count);
        for (SearchHit hit : result.getHits()) {
            String json = hit.getSourceAsString();
            ItemDoc itemDoc = JSONUtil.toBean(json, ItemDoc.class);
            System.out.println(itemDoc);
        }
    }

    // 构建排序+分页
    @Test
    public void testBuildSortQuery() throws IOException {
        // 创建请求对象
        SearchRequest request = new SearchRequest("item");
        // 请求体
        request.source().sort("price", SortOrder.DESC)
                .from(0).size(5);
        // 请求
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        SearchHits result = response.getHits();
        long count = result.getTotalHits().value;
        System.out.println(count);
        for (SearchHit hit : result.getHits()) {
            String json = hit.getSourceAsString();
            ItemDoc itemDoc = JSONUtil.toBean(json, ItemDoc.class);
            System.out.println(itemDoc);
        }
    }

    // 构建高亮
    @Test
    public void testBuildHighLightQuery() throws IOException {
        // 创建请求对象
        SearchRequest request = new SearchRequest("item");
        // 请求体
        request.source().query(QueryBuilders.multiMatchQuery("脱脂牛奶","name", "category"));
        request.source().highlighter(SearchSourceBuilder.highlight()
                .field("name")
                .preTags("<em>")
                .postTags("</em>"));
        // 请求
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        // 解析高亮数据
        SearchHits result = response.getHits();
        long count = result.getTotalHits().value;
        System.out.println(count);
        for (SearchHit hit : result.getHits()) {
            String json = hit.getSourceAsString();
            ItemDoc itemDoc = JSONUtil.toBean(json, ItemDoc.class);
            System.out.println(itemDoc);
            System.out.println(hit.getHighlightFields());
        }
    }

    // 构建聚合
    @Test
    public void testBuildAgg() throws IOException {
        // 创建请求对象
        SearchRequest request = new SearchRequest("item");
        // 请求体
        request.source().aggregation(AggregationBuilders
                .terms("category_agg")// 类型 + 名
                .field("category")// 聚合字段
                .size(15));
        // 请求
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        // 解析聚合数据
        Aggregations aggregations = response.getAggregations();
        Terms s =  aggregations.get("category_agg");
        // 从聚合中category_agg获取桶
        List<? extends Terms.Bucket> buckets = s.getBuckets();
        // 桶里面的数据
        for (Terms.Bucket bucket : buckets) {
            // 获取分类的数据名字
            String keyAsString = bucket.getKeyAsString();
            // 数据有多少
            long docCount = bucket.getDocCount();

            System.out.println(keyAsString+":"+docCount);
        }
    }
}
